using System;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.HtmlControls;
using System.ComponentModel;
using System.Globalization;

using AjaxControlToolkit;

using BizElements.BusinessLayer;

namespace BizElements.Web
{
    /// <summary>
    /// <b>CalendarPopup</b> control bound to a business class property.
    /// </summary>
    [DefaultProperty("SelectedValue"), ToolboxData("<{0}:BoundCalendar runat=server></{0}:BoundCalendar>")]
    [DefaultEvent("DateChanged")]
    public class BoundCalendar : WebControl, INamingContainer, IBoundControl, IValidator
    {
        #region Child controls.

        CalendarExtender ajaxCalendarExtender = new CalendarExtender();
        TextBox dateTextBox = new TextBox();
        Label readOnlyLabel = new Label();
        Image image = new Image();
        Label errorIndicator = new Label();
        Literal br = new Literal();
        Label errorLabel = new Label();
        Button autoPostBackButton = new Button();

        #endregion

        #region CTor and CreateChildControls.

        /// <summary>
        /// Initializes a new instance of the <see cref="BoundCalendar"/> class.
        /// </summary>
        public BoundCalendar()
        {
            this.Style["white-space"] = "nowrap";

            this.ajaxCalendarExtender.ID = "ext";

            this.dateTextBox.ID = "txt";
            this.dateTextBox.AutoCompleteType = AutoCompleteType.Disabled;

            this.readOnlyLabel.ID = "lbl";
            this.readOnlyLabel.EnableViewState = false;
            this.readOnlyLabel.Visible = false;

            this.image.ID = "img";
            this.image.Style["cursor"] = "pointer";
            this.image.EnableViewState = false;

            this.errorIndicator.ID = "errind";
            this.errorIndicator.Text = "*";
            this.errorIndicator.ForeColor = System.Drawing.Color.Red;
            this.errorIndicator.EnableViewState = false;
            this.errorIndicator.Visible = false;

            this.br.Text = "<br />";
            this.br.EnableViewState = false;

            this.errorLabel.ID = "errmsg";
            this.errorLabel.ForeColor = System.Drawing.Color.Red;
            this.errorLabel.EnableViewState = false;

            this.autoPostBackButton.ID = "btn";
            this.autoPostBackButton.Style["display"] = "none";
        }

        /// <summary>
        /// Called by the ASP.NET page framework to notify server controls that use composition-based 
        /// implementation to create any child controls they contain in preparation for posting back or rendering. 
        /// </summary>
        protected override void CreateChildControls()
        {
            this.Controls.Clear();            
            this.Controls.Add(this.dateTextBox);
            this.Controls.Add(this.readOnlyLabel);
            this.Controls.Add(this.image);
            this.Controls.Add(this.errorIndicator);
            this.Controls.Add(this.ajaxCalendarExtender);
            this.Controls.Add(this.br);
            this.Controls.Add(this.errorLabel);
            this.Controls.Add(this.autoPostBackButton);
        }

        #endregion

        #region OnInit - add to page validators.

        /// <summary>
        /// Raises the <b>Init</b> event.
        /// </summary>
        /// <param name="e">An <b>EventArgs</b> object that contains the event data.</param>
        protected override void OnInit(EventArgs e)
        {
            base.OnInit(e);
            AddMyselfToParentPageValidators();
        }

        private void AddMyselfToParentPageValidators()
        {
            this.Page.Validators.Add(this);
        }

        #endregion

        #region Render - define target controls IDs, render error, read-only mode.

        /// <summary>Sets CalendarExtender.TargetControlID property.</summary>
        protected override void OnPreRender(EventArgs e)
        {
            this.ajaxCalendarExtender.TargetControlID = this.dateTextBox.ID;
            if (this.ImageVisible && !string.IsNullOrEmpty(this.image.ImageUrl))
                this.ajaxCalendarExtender.PopupButtonID = this.image.ID;

            this.autoPostBackButton.Visible = this.AutoPostBack;
            if (this.AutoPostBack)
                AppendAutoPostBackScriptToOnClientDateSelectionChanged();

            base.OnPreRender(e);
        }

        private void AppendAutoPostBackScriptToOnClientDateSelectionChanged()
        {
            string autoPostBackScript = string.Format("$get(\"{0}\").click();", this.autoPostBackButton.ClientID);
            if (string.IsNullOrEmpty(this.OnClientDateSelectionChanged))
            {
                this.OnClientDateSelectionChanged = autoPostBackScript;
            }
            else
            {
                this.OnClientDateSelectionChanged = TextUtil.EnsureSuffix(this.OnClientDateSelectionChanged.Trim(), ";");
                this.OnClientDateSelectionChanged += " " + autoPostBackScript;
            }
        }

        /// <summary>
        /// Renders the control to the specified HTML writer.
        /// </summary>
        /// <param name="writer">The <see cref="System.Web.UI.HtmlTextWriter"/> object that receives the control content.</param>
        protected override void Render(HtmlTextWriter writer)
        {
            if (this.FieldCaptionIsDefaultToolTip && string.IsNullOrEmpty(this.ToolTip) && this.bizField != null)
                this.ToolTip = bizField.Caption;

            bool inReadOnlyMode = BoundControlHelper.IsInReadOnlyMode(this.AccessMode, this.BusinessField);
            ApplyAccessMode(inReadOnlyMode);
            RenderErrorMesage();
            base.Render(writer);
        }

        private void ApplyAccessMode(bool inReadOnlyMode)
        {
            // Can't use "Visible = false" because we want Text property encapsulates txtText.Text property and depends on TextBox's ViewState implementation.
            this.dateTextBox.Style["display"] = (inReadOnlyMode) ? "none" : "";
            this.readOnlyLabel.Text = this.dateTextBox.Text;
            this.readOnlyLabel.Visible = inReadOnlyMode;
            if (inReadOnlyMode)
            {
                this.image.Visible = false;
                this.autoPostBackButton.Visible = false;
            }
        }

        private void RenderErrorMesage()
        {
            bool noErrors = string.IsNullOrEmpty(this.ErrorText);
            if (noErrors)
            {
                this.errorLabel.Visible = this.br.Visible = this.errorIndicator.Visible = false;
            }
            else
            {
                switch (this.ErrorLocation)
                {
                    case ErrorLocation.Below:
                        this.errorIndicator.Visible = false;
                        this.br.Visible = true;
                        this.errorLabel.Visible = true;
                        break;

                    case ErrorLocation.Right:
                        this.errorIndicator.Visible = false;
                        this.br.Visible = false;
                        this.errorLabel.Visible = true;
                        break;

                    case ErrorLocation.ValidationSummary:
                        this.errorIndicator.Visible = true;
                        this.br.Visible = false;
                        this.errorLabel.Visible = false;
                        break;

                    default:
                        // Same as ErrorLocation.Below.
                        this.errorIndicator.Visible = false;
                        this.br.Visible = true;
                        this.errorLabel.Visible = true;
                        break;
                }
            }
        }

        #endregion

        /// <summary>
        /// Occurs when the value changes in browser and <see cref="AutoPostBack"/> property is set to <b>true</b>.
        /// </summary>
        [Description("Occurs when the value changes in browser. Requires that AutoPostBack is set to true.")]
        public event EventHandler DateChanged
        {
            add { this.autoPostBackButton.Click += value; }
            remove { this.autoPostBackButton.Click -= value; }
        }

        #region IBoundControl.

        FieldAccessMode accessMode = FieldAccessMode.Automatic;

        /// <summary>
        /// Gets or sets the value which indicates whether the <b>BoundAutoComplete</b> can change data in the bound field.
        /// </summary>
        [Bindable(false)]
        [Category("Behavior")]
        [DefaultValue(typeof(FieldAccessMode), "Automatic")]
        [Description("Indicates whether the contents of the control can be changed.")]
        public virtual FieldAccessMode AccessMode
        {
            get { return this.accessMode; }
            set { this.accessMode = value; }
        }

        IBindableField bizField;

        /// <summary>
        /// Gets or sets the business class' property to which the control is bound. Set programmatically.
        /// </summary>
        [Description("Business class' property to which the control is bound. Set programmatically.")]
        [Browsable(false)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public virtual IBindableField BusinessField
        {
            get { return this.bizField; }
            set { this.bizField = value; }
        }

        /// <summary>
        /// Appends all errors in the collection to the <see cref="ErrorText"/>.
        /// </summary>
        /// <param name="rules">Collection of broken rules.</param>
        /// <param name="formatter">The <see cref="IMessageFormatter"/> object used to format the messages contained in the collection.</param>
        public virtual void AppendError(BusinessRuleCollection rules, IMessageFormatter formatter)
        {
            BusinessRuleCollection brokenRulesForThisControl = rules.GetRulesForField(this.BusinessField.BindingName, true);
            this.ErrorText += brokenRulesForThisControl.ToString(formatter) + " ";
        }

        /// <summary>
        /// Clears errors. Same as setting the <see cref="ErrorText"/> to empty string.
        /// </summary>
        public virtual void ClearError()
        {
            this.ErrorText = "";
        }

        /// <summary>Gets the name of the control property which is bound two-way to a business object field: <b>SelectedValue</b></summary>
        [Browsable(false)]
        public string TwoWayBoundProperty
        {
            get { return "SelectedValue"; }
        }

        /// <summary>Returns <b>null</b>.</summary>
        [Browsable(false)]
        public string[] OneWayBoundProperties
        {
            get { return null; }
        }

        /// <summary>Gets error label control which displays errors associated with the given field.</summary>
        [Browsable(false)]
        public ITextControl ErrorLabel
        {
            get { return this.errorLabel; }
        }

        /// <summary>Not implemented. Returns <b>null</b>.</summary>
        [Browsable(false)]
        ITextControl IBoundControl.CaptionLabel
        {
            get { return null; }
        }

        /// <summary>Not implemented. Returns <b>null</b>.</summary>
        [Browsable(false)]
        ITextControl IBoundControl.TooltipLabel
        {
            get { return null; }
        }

        /// <summary>Not implemented. Returns <b>null</b>.</summary>
        [Browsable(false)]
        Control IBoundControl.RequiredFieldIndicatorControl
        {
            get { return null; }
        }

        #endregion

        #region IValidator.

        /// <summary>
        /// Gets the value contained in the <see cref="ErrorText"/> property if a validation summary has been specified as location for errors.
        /// </summary>
        string IValidator.ErrorMessage
        {
            get { return (this.ErrorLocation == ErrorLocation.ValidationSummary) ? this.ErrorText : ""; }
            set { }
        }

        /// <summary>
        /// Does nothing. Validation logic is performed elsewhere (eg. business class).
        /// </summary>
        void IValidator.Validate()
        {
        }

        /// <summary>
        /// Gets a value which indicates whether an the <see cref="ErrorText"/> property contains error description.
        /// </summary>
        bool IValidator.IsValid
        {
            get { return string.IsNullOrEmpty(this.ErrorText); }
            set { }
        }

        #endregion

        #region Control properties which effect multiple child controls.

        /// <summary>
        /// Selected value.
        /// </summary>
        [Bindable(true, BindingDirection.TwoWay)]
        [Browsable(false)]
        public virtual DateTime? SelectedValue
        {
            get 
            { 
                return NumberParser.ParseDateTime(this.dateTextBox.Text, DateTimeStyles.None, GetCulture(), GetDateFormat());
            }
            set
            {
                this.dateTextBox.Text = (value.HasValue) ? value.Value.ToString(GetDateFormat(), GetCulture()) : "";
                this.ajaxCalendarExtender.SelectedDate = value;
            }
        }

        private CultureInfo GetCulture()
        {
            return CultureInfo.CurrentCulture;
        }

        private string GetDateFormat()
        {
            return string.IsNullOrEmpty(this.ajaxCalendarExtender.Format) ? null : this.ajaxCalendarExtender.Format;
        }

        /// <summary>Gets or sets whether <see cref="UserSession.DefaultDateFormat"/> is used for parsing purposes instead of format specified in <see cref="Format"/> property.</summary>
        [Bindable(false), Category("Behavior"), DefaultValue(typeof(bool), "false"),
        Description("Indicates whether UserSession.DefaultDateFormat is used for parsing purposes instead of format specified in Format property.")]
        public virtual bool UseSessionFormat { get; set; }

        /// <summary>
        /// Gets or sets a value indicating whether the Web server control is enabled.
        /// </summary>
        [DefaultValue(true)]
        [Category("Behavior")]
        [Themeable(false)]
        [Bindable(true)]
        [Description("Indicates whether the Web server control is enabled.")]
        public override bool Enabled
        {
            get { return base.Enabled; }
            set
            {
                base.Enabled = value;
                this.image.Enabled = value;
                this.ajaxCalendarExtender.Enabled = value;
                this.autoPostBackButton.Enabled = false;
            }
        }

        /// <summary>
        /// Gets or sets a value that indicates whether an automatic postback to the server occurs when the value changes on the client.
        /// </summary>
        [Themeable(false)]
        [Category("Behavior")]
        [DefaultValue(false)]
        [Description("Indicates whether an automatic postback to the server occurs when the selected value changes on the client.")]
        public virtual bool AutoPostBack { get; set; }

        bool fieldCaptionIsDefaultToolTip = true;

        /// <summary>
        /// Gets or sets whether the caption of the bound field is used as default tooltip.
        /// </summary>
        /// <value><b>true</b> if field caption is default tooltop; <b>false</b> otherwise. Default is <b>true</b>.</value>
        [Bindable(false)]
        [Category("Behavior")]
        [DefaultValue(true)]
        [Description("Whether the caption of the bound field is used as default tooltip.")]
        public virtual bool FieldCaptionIsDefaultToolTip
        {
            get { return this.fieldCaptionIsDefaultToolTip; }
            set { this.fieldCaptionIsDefaultToolTip = value; }
        }

        #endregion

        #region Error properties.

        /// <summary>
        /// Gets or sets the CSS Class name applied to the error label.
        /// </summary>
        [Bindable(false)]
        [Category("Appearance")]
        [DefaultValue(null)]
        [Description("CSS Class name applied to the error label.")]
        public virtual string ErrorCss
        {
            get { return this.errorLabel.CssClass; }
            set { this.errorLabel.CssClass = this.errorIndicator.CssClass = value; }
        }

        /// <summary>
        /// Gets or sets the color of the error text.
        /// </summary>
        [Bindable(false)]
        [Category("Appearance")]
        [DefaultValue(typeof(System.Drawing.Color), "Red")]
        [Description("Color of the error text.")]
        [TypeConverter(typeof(WebColorConverter))]
        public virtual System.Drawing.Color ErrorColor
        {
            get { return this.errorLabel.ForeColor; }
            set { this.errorLabel.ForeColor = this.errorIndicator.ForeColor = value; }
        }

        /// <summary>
        /// Gets or sets the error text displayed in the error label or in the page's validation summary. 
        /// Usually set programmatically.
        /// </summary>
        [Bindable(false), Category("Appearance"),
        Description("Error text displayed in the error label or in the page's validation summary. Usually set programmatically.")]
        [DefaultValue("")]
        public virtual string ErrorText
        {
            get { return this.errorLabel.Text ?? ""; }
            set { this.errorLabel.Text = value ?? ""; }
        }

        /// <summary>
        /// Gets or sets the indicator placed by the control if it contains an invalid value. 
        /// Displayed only when the error text is displayed in the validation summary.
        /// </summary>
        [Bindable(false)]
        [Category("Appearance")]
        [DefaultValue("*")]
        [Description("Indicator placed by the control if it contains an invalid value. Displayed only when the error text is displayed in the validation summary.")]
        public virtual string ErrorIndicator
        {
            get { return this.errorIndicator.Text ?? ""; }
            set { this.errorIndicator.Text = value ?? ""; }
        }

        ErrorLocation errorLocation = ErrorLocation.Below;

        /// <summary>
        /// Gets or sets the value which specifies where the error text is located.
        /// </summary>
        [Bindable(false)]
        [Category("Appearance")]
        [DefaultValue(typeof(ErrorLocation), "Below")]
        [Description("Specifies where the error text is located.")]
        public virtual ErrorLocation ErrorLocation
        {
            get { return this.errorLocation; }
            set { this.errorLocation = value; }
        }

        #endregion

        #region TextBox properties.

        /// <summary>
        /// Gets or sets the access key that allows you to quickly navigate to the Web server control.
        /// </summary>
        /// <value>The access key for quick navigation to the Web server control. The default value is Empty, which indicates that this property is not set.</value>
        [Category("Behavior")]
        [DefaultValue("")]
        [Description("Access key that allows you to quickly navigate to the Web server control.")]
        public override string AccessKey
        {
            get { return this.dateTextBox.AccessKey; }
            set { this.dateTextBox.AccessKey = value; }
        }

        /// <summary>Gets the TextBox which contains the selected date.</summary>
        [Description("Gets the TextBox which contains the selected date.")]
        [Browsable(false)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public TextBox TextBox
        {
            get { return this.dateTextBox; }
        }

        /// <summary>
        /// Gets the ClientID assigned to the textbox control used in the popup control.
        /// </summary>
        [Bindable(false)]
        [Browsable(false)]
        [Category("Misc")]
        [Description("ClientID assigned to the textbox control used in the popup control.")]
        public string TextBoxClientID
        {
            get { return this.dateTextBox.ClientID; }
        }

        /// <summary>
        /// Gets or sets the Cascading Style Sheet (CSS) class for textbox control that displays selected date.
        /// </summary>
        [Bindable(false), Category("Behavior"), DefaultValue(typeof(string), ""),
        Description("Cascading Style Sheet (CSS) class for textbox control that displays selected date.")]
        public virtual string TextBoxCssClass
        {
            get { return this.dateTextBox.CssClass; }
            set { this.dateTextBox.CssClass = value; }
        }

        /// <summary>
        /// Gets or sets the display width of the text box in characters.
        /// </summary>
        /// <value>The display width, in characters, of the text box. The default is 0, which indicates that the property is not set.</value>
        [Category("Appearance")]
        [DefaultValue(0)]
        [Description("Display width of the text box in characters.")]
        public virtual int TextBoxColumns
        {
            get { return this.dateTextBox.Columns; }
            set { this.dateTextBox.Columns = value; }
        }

        /// <summary>
        /// Gets or sets the width of the text box.
        /// </summary>
        [Category("Appearance")]
        [Description("Width of the control.")]
        public virtual Unit TextBoxWidth
        {
            get { return this.dateTextBox.Width; }
            set { this.dateTextBox.Width = value; }
        }

        #endregion

        #region Image properties.

        /// <summary>Gets the image control displayed next to date textbox.</summary>
        [Description("Image control displayed next to date textbox.")]
        [Browsable(false)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public Image Image
        {
            get { return this.image; }
        }

        /// <summary>
        /// Gets the ClientID assigned to the image control used in the popup control.
        /// </summary>
        [Bindable(false)]
        [Browsable(false)]
        [Category("Misc")]
        [Description("ClientID assigned to the image control used in the popup control.")]
        public string ImageClientID
        {
            get { return this.image.ClientID; }
        }

        /// <summary>
        /// Gets or sets the source of the image file to display.
        /// </summary>
        [Category("Behavior")]
        [Description("Source (URL) of the image file to display.")]
        [DefaultValue("")]
        [UrlProperty]
        public virtual string ImageUrl
        {
            get { return this.image.ImageUrl; }
            set { this.image.ImageUrl = value; }
        }

        /// <summary>
        /// Gets or sets a value that indicates whether the image is visible.
        /// </summary>
        [DefaultValue(true)]
        [Bindable(true)]
        [Category("Behavior")]
        [Description("Indicates whether the image is visible.")]
        public virtual bool ImageVisible
        {
            get { return this.image.Visible; }
            set { this.image.Visible = value; }
        }

        /// <summary>
        /// Gets or sets the Cascading Style Sheet (CSS) class applied to image.
        /// </summary>
        [Category("Appearance")]
        [CssClassProperty]
        [DefaultValue("")]
        [Description("CSS class applied to image.")]
        public virtual string ImageCssClass
        {
            get { return this.image.Attributes["class"] ?? ""; }
            set
            {
                if (value == null)
                    this.image.Attributes.Remove("class");
                else
                    this.image.Attributes["class"] = value;
            }
        }

        /// <summary>Gets or sets the alignment of the image relative to other Web page elements.</summary>
        [Category("Appearance")]
        [Description("Alignment of the image relative to other Web page elements")]
        public virtual ImageAlign ImageAlign
        {
            get { return this.image.ImageAlign; }
            set { this.image.ImageAlign = value; }
        }

        /// <summary>Gets or sets the alternative caption the browser displays if an image is unavailable or currently downloading and not yet finished.</summary>
        [Localizable(true)]
        [Description("A string that contains the alternative caption for the browser to use when the image is unavailable.")]
        [DefaultValue("")]
        [Category("Appearance")]
        public virtual string ImageAlternateText
        {
            get { return this.image.AlternateText; }
            set { this.image.AlternateText = value; }
        }

        /// <summary>Gets or sets the width of a frame for an image.</summary>
        [Category("Appearance")]
        [DefaultValue(typeof(Unit), "")]
        [Description("The width (in pixels) of a frame for an image.")]
        public virtual Unit ImageBorderWidth
        {
            get { return this.image.BorderWidth; }
            set { this.image.BorderWidth = value; }
        }

        /// <summary>Gets or sets the height of the image.</summary>
        [DefaultValue(typeof(Unit), "")]
        [Description("The height of the image.")]
        [Category("Layout")]
        public virtual Unit ImageHeight
        {
            get { return this.image.Height; }
            set { this.image.Height = value; }
        }

        /// <summary>Gets or sets the width of the image.</summary>
        [Category("Layout")]
        [DefaultValue(typeof(Unit), "")]
        [Description("The width of the image.")]
        public virtual Unit ImageWidth
        {
            get { return this.image.Width; }
            set { this.image.Width = value; }
        }

        #endregion

        #region Read-only label properties.

        /// <summary>
        /// Gets or sets the Cascading Style Sheet (CSS) class rendered by the Web server control 
        /// on the client when the control is in read-only mode.
        /// </summary>
        [Bindable(false), Category("Behavior"), DefaultValue(typeof(string), ""),
        Description("Cascading Style Sheet (CSS) class rendered by the Web server control on the client when the control is in read-only mode.")]
        public virtual string ReadOnlyCssClass
        {
            get { return this.readOnlyLabel.CssClass; }
            set { this.readOnlyLabel.CssClass = value; }
        }

        #endregion

        #region CalendarExtender Properties.

        /// <summary>
        /// Name of the Cascading Style Sheet class used to style the calendar.
        /// </summary>
        [DefaultValue("")]
        [Description("Name of the Cascading Style Sheet class used to style the calendar.")]
        public override string CssClass
        {
            get { return this.ajaxCalendarExtender.CssClass; }
            set { this.ajaxCalendarExtender.CssClass = value; }
        }

        /// <summary>
        /// Format string used to display the selected date. The default value is "d".
        /// </summary>
        [DefaultValue("d")]
        [Description("Format string used to display the selected date. The default value is 'd'.")]
        public virtual string Format
        {
            get { return this.ajaxCalendarExtender.Format; }
            set { this.ajaxCalendarExtender.Format = value; }
        }

        /// <summary>
        /// Format string used to display today's date. The default value is "MMMM d, yyyy".
        /// </summary>
        [DefaultValue("MMMM d, yyyy")]
        [Description("Format string used to display today's date. The default value is 'MMMM d, yyyy'.")]
        public virtual string TodaysDateFormat
        {
            get { return this.ajaxCalendarExtender.TodaysDateFormat; }
            set { this.ajaxCalendarExtender.TodaysDateFormat = value; }
        }

        /// <summary>
        /// Format string used to display Days Mode Title. The default value is "MMMM, yyyy".
        /// </summary>
        [DefaultValue("MMMM, yyyy")]
        [Description("Format string used to display Days Mode Title. The default value is 'MMMM, yyyy'.")]
        public virtual string DaysModeTitleFormat
        {
            get { return this.ajaxCalendarExtender.DaysModeTitleFormat; }
            set { this.ajaxCalendarExtender.DaysModeTitleFormat = value; }
        }

        /// <summary>
        /// Whether time should be cleared in edited date/time.
        /// </summary>
        [DefaultValue(false)]
        [Description("Whether time should be cleared in edited date/time.")]
        public virtual bool ClearTime
        {
            get { return this.ajaxCalendarExtender.ClearTime; }
            set { this.ajaxCalendarExtender.ClearTime = value; }
        }

        /// <summary>
        /// Whether this behavior is available for the current element.
        /// </summary>
        [DefaultValue(true)]
        [Description("Whether this behavior is available for the current element.")]
        public virtual bool EnabledOnClient
        {
            get { return this.ajaxCalendarExtender.EnabledOnClient; }
            set { this.ajaxCalendarExtender.EnabledOnClient = value; }
        }

        /// <summary>
        /// Whether changing modes is animated.
        /// </summary>
        [DefaultValue(true)]
        [Description("Whether changing modes is animated.")]
        public virtual bool Animated
        {
            get { return this.ajaxCalendarExtender.Animated; }
            set { this.ajaxCalendarExtender.Animated = value; }
        }

        /// <summary>
        /// Gets or sets the first day of week.
        /// </summary>
        [DefaultValue(FirstDayOfWeek.Default)]
        [Description("Gets or sets the first day of week.")]
        public virtual FirstDayOfWeek FirstDayOfWeek
        {
            get { return this.ajaxCalendarExtender.FirstDayOfWeek; }
            set { this.ajaxCalendarExtender.FirstDayOfWeek = value; }
        }

        /// <summary>
        /// Gets or sets the popup position of the calendar. The default value is BottomLeft.
        /// </summary>
        [DefaultValue(CalendarPosition.BottomLeft)]
        [Description("Indicates where you want the calendar displayed, bottom or top of the textbox.")]
        public virtual CalendarPosition PopupPosition
        {
            get { return this.ajaxCalendarExtender.PopupPosition; }
            set { this.ajaxCalendarExtender.PopupPosition = value; }
        }

        /// <summary>
        /// Gets or sets the default view of the calender. The default value is Days.
        /// </summary>
        [DefaultValue(CalendarDefaultView.Days)]
        [Description("Default view of the calendar when it first pops up.")]
        public virtual CalendarDefaultView DefaultView
        {
            get { return this.ajaxCalendarExtender.DefaultView; }
            set { this.ajaxCalendarExtender.DefaultView = value; }
        }

        /// <summary>
        /// Gets or sets the client script that executes immediately before the calendar is displayed.
        /// </summary>
        [DefaultValue("")]
        [Description("Gets or sets the client script that executes immediately before the calendar is displayed.")]
        public virtual string OnClientShowing
        {
            get { return this.ajaxCalendarExtender.OnClientShowing; }
            set { this.ajaxCalendarExtender.OnClientShowing = value; }
        }

        /// <summary>
        /// Gets or sets the client script that executes immediately after the calendar is displayed.
        /// </summary>
        [DefaultValue("")]
        [Description("Gets or sets the client script that executes immediately after the calendar is displayed.")]
        public virtual string OnClientShown
        {
            get { return this.ajaxCalendarExtender.OnClientShown; }
            set { this.ajaxCalendarExtender.OnClientShown = value; }
        }

        /// <summary>
        /// Gets or sets the client script that executes immediately before the calendar is hidden.
        /// </summary>
        [DefaultValue("")]
        [Description("Gets or sets the client script that executes immediately before the calendar is hidden.")]
        public virtual string OnClientHiding
        {
            get { return this.ajaxCalendarExtender.OnClientHiding; }
            set { this.ajaxCalendarExtender.OnClientHiding = value; }
        }

        /// <summary>
        /// Gets or sets the client script that executes immediately after the calendar is hidden.
        /// </summary>
        [DefaultValue("")]
        [Description("Gets or sets the client script that executes immediately after the calendar is hidden.")]
        public virtual string OnClientHidden
        {
            get { return this.ajaxCalendarExtender.OnClientHidden; }
            set { this.ajaxCalendarExtender.OnClientHidden = value; }
        }

        /// <summary>
        /// Gets or sets the script that executes when a new date is selected.
        /// </summary>
        [DefaultValue("")]
        [Description("Gets or sets the script that executes when a new date is selected.")]
        public virtual string OnClientDateSelectionChanged
        {
            get { return this.ajaxCalendarExtender.OnClientDateSelectionChanged; }
            set { this.ajaxCalendarExtender.OnClientDateSelectionChanged = value; }
        }

        /// <summary>
        /// Gets or sets the property of the start date for range.
        /// </summary>
        [DefaultValue(null)]
        [Description("")]
        public DateTime? StartDate
        {
            get { return this.ajaxCalendarExtender.StartDate; }
            set { this.ajaxCalendarExtender.StartDate = value; }
        }

        /// <summary>
        /// Gets or sets the property of the end date for range.
        /// </summary>
        [DefaultValue(null)]
        [Description("")]
        public DateTime? EndDate
        {
            get { return this.ajaxCalendarExtender.EndDate; }
            set { this.ajaxCalendarExtender.EndDate = value; }
        }

        #endregion
    }
}
